/*
 * Math and Statistics Library
 * 
 * This library contains classes and functions for doing Database operations, Unit conversions and Math calculations.
 * 
 * 3/01/08 -- Coding started with Ke Sun.
 * 
 * Copyright (c) 2008 Ke Sun
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
 * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Collections;

namespace Chengdu
{
    /// <summary>
    /// Class library containing functions for unit conversion.
    /// </summary>
    public class UnitConvert
    {
        /// <summary>
        /// Time conversion formulas.
        /// </summary>
        public class Time
        {
            #region Methods
            public double CD_dayToSec(double day)
            {
                return day * 86400;
            }

            public double CD_yearToSec(double year)
            {
                return year * 3.156 * Math.Pow(10, 7);
            }
            #endregion
        }

        /// <summary>
        /// Length conversion formulas.
        /// </summary>
        public class Length
        {
            #region Methods
            public double CD_ftToM(double ft)
            {
                return ft * 0.3048;
            }

            public double CD_inToM(double inch)
            {
                return inch * 0.0254;
            }

            public double CD_mileToM(double mile)
            {
                return mile * 1609;
            }

            public double CD_nauticalmileToM(double nmile)
            {
                return nmile * 1853;
            }

            public double CD_parsecToM(double parsec)
            {
                return parsec * 3.085 * Math.Pow(10, 16);
            }
            #endregion
        }

        /// <summary>
        /// Area conversion formulas.
        /// </summary>
        public class Area
        {
            #region Methods
            public double CD_acreToM2(double acre)
            {
                return acre * 4047;
            }

            public double CD_ft2ToM2(double ft2)
            {
                return ft2 * 0.09294;
            }

            public double CD_in2ToM2(double in2)
            {
                return in2 * 6.452 * Math.Pow(10, -4);
            }
            #endregion
        }

        /// <summary>
        /// Pressure conversion formulas.
        /// </summary>
        public class Pressure
        {
            #region Methods
            public double CD_barToPa(double bar)
            {
                return bar * Math.Pow(10, 5);
            }

            public double CD_dyneCM2ToPa(double dyneCM2)
            {
                return dyneCM2 * 0.1;
            }

            public double CD_inchMercuryToPa(double inchMercury)
            {
                return inchMercury * 3377;
            }

            public double CD_inchWaterToPa(double inchWater)
            {
                return inchWater * 248.82;
            }

            public double CD_kgPerCM2ToPa(double kgPerCM2)
            {
                return kgPerCM2 * 98070;
            }

            public double CD_lbPerFT2ToPa(double lbPerFT2)
            {
                return lbPerFT2 * 47.89;
            }

            public double CD_lbPerIN2ToPa(double lbPerIN2)
            {
                return lbPerIN2 * 6897;
            }

            public double CD_mbarToPa(double mbar)
            {
                return mbar * 100;
            }

            public double CD_micronMercuryToPa(double micronMercury)
            {
                return micronMercury * 0.1333;
            }

            public double CD_mmMercuryToPa(double mmMercury)
            {
                return mmMercury * 133.3;
            }

            public double CD_stdAtmToPa(double stdAtm)
            {
                return stdAtm * 1.013 * Math.Pow(10, 5);
            }
            #endregion
        }

        /// <summary>
        /// Volume conversion formulas.
        /// </summary>
        public class Volume
        {
            #region Methods
            public double CD_ft3ToM3(double ft3)
            {
                return ft3 * 0.02831;
            }

            public double CD_in3ToM3(double in3)
            {
                return in3 * 1.639 * Math.Pow(10, -5);
            }

            public double CD_litersToM3(double liters)
            {
                return liters * 0.001;
            }

            public double CD_usgallonsToM3(double usgallons)
            {
                return usgallons * 3.785 * Math.Pow(10, -3);
            }
            #endregion
        }

        /// <summary>
        /// Mass conversion formulas.
        /// </summary>
        public class Mass
        {
            #region Methods
            public double CD_lbToKg(double lb)
            {
                return lb * 0.4535;
            }
            #endregion
        }

        /// <summary>
        /// Power conversion formulas.
        /// </summary>
        public class Power
        {
            #region Methods
            public double CD_hpToW(double hp)
            {
                return hp * 745.71;
            }

            public double CD_btuPerHourToW(double btuPerHour)
            {
                return btuPerHour * 0.2931;
            }
            #endregion
        }

        /// <summary>
        /// Force conversion formulas.
        /// </summary>
        public class Force
        {
            #region Methods
            #region gram (g) to other units.
            public double CD_gToKg(double g)
            {
                return g * 0.001;
            }

            public double CD_gToN(double g)
            {
                return g * 0.009807;
            }

            public double CD_gToKN(double g)
            {
                return g * 9.807 * Math.Pow(10, -6);
            }

            public double CD_gToOz(double g)
            {
                return g * 0.03527;
            }

            public double CD_gToLbf(double g)
            {
                return g * 2.205 * Math.Pow(10, -3);
            }

            public double CD_gToTonShort(double g)
            {
                return g * 1.102 * Math.Pow(10, -6);
            }

            public double CD_gToTonLong(double g)
            {
                return g * 9.842 * Math.Pow(10, -7);
            }

            public double CD_gToMetricTon(double g)
            {
                return g * Math.Pow(10, -6);
            }
            #endregion

            #region kilogram force (kgf) to other units.
            public double CD_kgToGram(double kg)
            {
                return kg * 1000;
            }

            public double CD_kgToN(double kg)
            {
                return kg * 9.807;
            }

            public double CD_kgToKN(double kg)
            {
                return kg * 9.807 * Math.Pow(10, -3);
            }

            public double CD_kgToOzf(double kg)
            {
                return kg * 35.27;
            }

            public double CD_kgToLbf(double kg)
            {
                return kg * 2.205;
            }

            public double CD_kgToTonShort(double kg)
            {
                return kg * 1.102 * Math.Pow(10, -3);
            }

            public double CD_kgToTonLong(double kg)
            {
                return kg * 9.842 * Math.Pow(10, -4);
            }

            public double CD_kgToMetricTon(double kg)
            {
                return kg * 0.001;
            }
            #endregion

            #region newton (N) to other units.
            public double CD_NewtonToGram(double Newton)
            {
                return Newton * 102;
            }

            public double CD_NewtonToKgram(double Newton)
            {
                return Newton * 0.102;
            }

            public double CD_NewtonToKn(double Newton)
            {
                return Newton * 0.001;
            }

            public double CD_NewtonToOzf(double Newton)
            {
                return Newton * 3.597;
            }

            public double CD_NewtonToLbf(double Newton)
            {
                return Newton * 0.2248;
            }

            public double CD_NewtonToTonShort(double Newton)
            {
                return Newton * 1.124 * Math.Pow(10, -4);
            }

            public double CD_NewtonToTonLong(double Newton)
            {
                return Newton * 1.004 * Math.Pow(10, -4);
            }

            public double CD_NewtonToMetricTon(double Newton)
            {
                return Newton * 1.02 * Math.Pow(10, -4);
            }
            #endregion

            #region ounce-force (ozf) to other units.
            public double CD_ozfToGram(double ozf)
            {
                return ozf * 28.35;
            }

            public double CD_ozfToKgf(double ozf)
            {
                return ozf * 0.02835;
            }

            public double CD_ozfToNewton(double ozf)
            {
                return ozf * 0.278;
            }

            public double CD_ozfToKNewton(double ozf)
            {
                return ozf * 2.78 * Math.Pow(10, -4);
            }

            public double CD_ozfToLbf(double ozf)
            {
                return ozf * 0.0625;
            }

            public double CD_ozfToTonShort(double ozf)
            {
                return ozf * 3.125 * Math.Pow(10, -5);
            }

            public double CD_ozfToTonLong(double ozf)
            {
                return ozf * 2.79 * Math.Pow(10, -5);
            }

            public double CD_ozfToMetricTon(double ozf)
            {
                return ozf * 2.835 * Math.Pow(10, -5);
            }
            #endregion

            #region pound-force (lbf) to other units.
            public double CD_lbfToGram(double lbf)
            {
                return lbf * 453.6;
            }

            public double CD_lbfToKGram(double lbf)
            {
                return lbf * 0.4536;
            }

            public double CD_lbfToKNewton(double lbf)
            {
                return lbf * 4.448 * Math.Pow(10, -3);
            }

            public double CD_lbfToOzf(double lbf)
            {
                return lbf * 16;
            }

            public double CD_lbfToTonShort(double lbf)
            {
                return lbf * 5 * Math.Pow(10, -4);
            }

            public double CD_lbfToTonLong(double lbf)
            {
                return lbf * 4.464 * Math.Pow(10, -4);
            }

            public double CD_lbfToMetricTon(double lbf)
            {
                return lbf * 4.536 * Math.Pow(10, -4);
            }
            #endregion

            #region ton, short (2000 lb) to other units.
            public double CD_tonShortToGram(double tonShort)
            {
                return tonShort * 9.072 * Math.Pow(10, 5);
            }

            public double CD_tonShortToKGram(double tonShort)
            {
                return tonShort * 9.072 * Math.Pow(10, 2);
            }

            public double CD_tonShortToNewton(double tonShort)
            {
                return tonShort * 8.896 * Math.Pow(10, 3);
            }

            public double CD_tonShortToKNewton(double tonShort)
            {
                return tonShort * 8.896;
            }

            public double CD_tonShortToOzf(double tonShort)
            {
                return tonShort * 3.2 * Math.Pow(10, 4);
            }

            public double CD_tonShortToLbf(double tonShort)
            {
                return tonShort * 2000;
            }

            public double CD_tonShortToTonLong(double tonShort)
            {
                return tonShort * 0.8929;
            }

            public double CD_tonShortToMetricTon(double tonShort)
            {
                return tonShort * 0.9072;
            }
            #endregion

            #region ton, long (2240 lb) to ton, short.
            public double CD_tonLongToTonShort(double tonLong)
            {
                return tonLong * 1.12;
            }
            #endregion

            #region metric ton (1000 kg) to kilogram force(kgf).
            public double CD_metricTonToKGram(double metricTon)
            {
                return metricTon * 1000;
            }
            #endregion
            #endregion
        }
    }

    /// <summary>
    /// Library for doing electrical calculations.
    /// </summary>
    public class Electrical
    {
        /// <summary>
        /// Function to calculate current running through a resistor.
        /// </summary>
        /// <param name="voltage">Voltage across resistor.</param>
        /// <param name="resistance">Resistance value of resistor.</param>
        /// <returns>Current value.</returns>
        public double CD_Current(double voltage, double resistance)
        {
            return voltage / resistance;
        }

        /// <summary>
        /// Function to calculate voltage value across a resistor.
        /// </summary>
        /// <param name="current">Current value passing through the resistor.</param>
        /// <param name="resistance">Resistance value of resistor.</param>
        /// <returns>Voltage value across resistor.</returns>
        public double CD_Voltage(double current, double resistance)
        {
            return current * resistance;
        }

        /// <summary>
        /// Function to calculate power from the current and resistance.
        /// </summary>
        /// <param name="current">Current value passing through resistor.</param>
        /// <param name="resistance">Resistance value of resistor.</param>
        /// <returns>Power value of resistor.</returns>
        public double CD_Power_I2R(double current, double resistance)
        {
            return current * current * resistance;
        }

        /// <summary>
        /// Function to calculate power from the current and voltage. 
        /// </summary>
        /// <param name="current">Current value passing through resistor.</param>
        /// <param name="voltage">Voltage value across resistor.</param>
        /// <returns>Power value of resistor.</returns>
        public double CD_Power_IV(double current, double voltage)
        {
            return current * voltage;
        }

        /// <summary>
        /// Function to calculate resistance of a resistor.
        /// </summary>
        /// <param name="voltage">Voltage across resistor.</param>
        /// <param name="current">Resistance value of resistor.</param>
        /// <returns>Resistance value.</returns>
        public double CD_Resistance(double voltage, double current)
        {
            return voltage / current;
        }

        /// <summary>
        /// Function to calculate the result of resistors in parallel.
        /// </summary>
        /// <param name="resistorValues">Array of resistor values.</param>
        /// <returns>Parallel resistor value.</returns>
        public double CD_ParallelResistor(double[] resistorValues)
        {
            if (resistorValues.Length > 1)
            {
                double pValue = resistorValues[0];

                for (int i = 1; i < resistorValues.Length; i++)
                {
                    pValue = 1 / (1 / pValue + 1 / resistorValues[i]);
                }

                return pValue;
            }
            else
            {
                throw new Exception("Chengdu_Math.parallelTransistor: The length of the transistor value array needs to be larger than 1.");
            }
        }

        /// <summary>
        /// Function to calculate the result of resistors in series.
        /// </summary>
        /// <param name="resistorValues">Array of resistor values.</param>
        /// <returns>Series resistor value.</returns>
        public double CD_SeriesResistor(double[] resistorValues)
        {
            if (resistorValues.Length > 1)
            {
                double sValue = resistorValues[0];

                for (int i = 1; i < resistorValues.Length; i++)
                {
                    sValue = sValue + resistorValues[i];
                }

                return sValue;
            }
            else
            {
                throw new Exception("Chengdu_Math.seriesTransistor: The length of the transistor value array needs to be larger than 1.");
            }
        }

        /// <summary>
        /// Function to calculate the voltage across a resistor acting as the voltage divider.
        /// </summary>
        /// <param name="resistors">An array of all resistor values.</param>
        /// <param name="resistorOfInterest">The resistor whose voltage value is of interest.</param>
        /// <param name="voltage">The voltage shared by the resistors.</param>
        /// <returns>Voltage value across the resistor of interest.</returns>
        public double CD_VoltageDivider(double[] resistors, double resistorOfInterest, double voltage)
        {
            double totalResistorValue = double.NaN;

            foreach (double rValue in resistors)
            {
                totalResistorValue += rValue;
            }

            return (resistorOfInterest / totalResistorValue * voltage);
        }
    }
    
    /// <summary>
    /// Math library for calculating resistance and voltage etc.
    /// </summary>
    public class MathLib
    {
        /// <summary>
        /// Function to calculate the average for an array of numbers.
        /// </summary>
        /// <param name="X">Input array of numbers.</param>
        /// <returns>Average value.</returns>
        public double CD_Average(double[] X)
        {
            // Sum of all the numbers.
            double sum = double.NaN;

            // Take the sum of all the numbers.
            for (int i = 0; i < X.Length; i++)
            {
                sum += X[i];
            }

            // Average value.
            double avg = sum / X.Length;

            return avg;
        }

        /// <summary>
        /// Function to calculate the Standard Deviation for an array of numbers.
        /// </summary>
        /// <param name="X">Input array of numbers.</param>
        /// <returns>Standard deviation value.</returns>
        public double CD_StandardDeviation(double[] X)
        {
            // Standard Deviation value.
            double stdv = double.NaN;

            // Get the average value of the number array.
            double avg = CD_Average(X);

            // Variance.
            double variance = double.NaN;

            // Calculate the Variance.
            for (int i = 0; i < X.Length; i++)
            {
                variance += Math.Pow((X[i] - avg), 2);
            }

            variance = variance / X.Length;

            // Calculate the Standard Deviation.
            stdv = Math.Pow(variance, 0.5);

            return stdv;
        }

        /// <summary>
        /// Function to calculate the Autocorrelation for an array of numbers, with a lag of k.
        /// </summary>
        /// <param name="X">Input array of numbers, assumed to be equi-spaced.</param>
        /// <param name="k">Lag, must be less than the length of X.</param>
        /// <returns>Autocorrelation coefficient.</returns>
        public double CD_Autocorrelation(double[] X, int k)
        {
            // Calculate the mean.
            double X_m = CD_Average(X);

            // Calculate the numerator for the autocorrelation function.
            double num = double.NaN;

            for (int i = 0; i < (X.Length - k); i++)
            {
                num += (X[i] - X_m) * (X[i + k] - X_m);
            }

            // Calculate the denominator for the autocorrelation function.
            double den = double.NaN;

            for (int i = 0; i < X.Length; i++)
            {
                den += Math.Pow((X[i] - X_m), 2);
            }

            // Calculate the autocorrelation coefficient.
            double r = num / den;

            return r;
        }

        /// <summary>
        /// Function to calculate a Power Series value.
        /// </summary>
        /// <param name="a">Coefficient array.</param>
        /// <param name="x">Input value.</param>
        /// <param name="c">Offset value.</param>
        /// <returns>Power series value.</returns>
        public double CD_PowerSeriesValue(double[] a, double x, double c)
        {
            // Create the value holder.
            double sum = double.NaN;

            // Calculate the power series values and sum them up.
            for (int i = 0; i < a.Length; i++)
            {
                sum += a[i] * Math.Pow(x - c, i);
            }

            // Return the value.
            return sum;
        }
    }

    /// <summary>
    /// Engineering statistics library for calculating Availability etc.
    /// </summary>
    public class EngStats
    {
        /// <summary>
        /// Calcualtes the Availability of a component.
        /// </summary>
        /// <param name="mtbf">Mean Time Between Failures. (Usually in hours)</param>
        /// <param name="mttr">Mean Time To Repair. (Usually in hours)</param>
        /// <returns>Availability.</returns>
        public double CD_Availability(double mtbf, double mttr)
        {
            return mtbf / (mtbf + mttr);
        }

        /// <summary>
        /// Calculates the Availability of a series of components.
        /// </summary>
        /// <param name="mtbf">Mean Time Between Failures for each component. (Usually in hours)</param>
        /// <param name="mttr">Mean Time To Repair for each component. (Usually in hours)</param>
        /// <returns>Series Availability.</returns>
        public double CD_SeriesAvailability(double[] mtbf, double[] mttr)
        {
            // Create an array for storing Availability. 
            double[] availability = new double[mtbf.Length];

            // Create the Series Availability.
            double seriesAvailability = 1;

            for (int i = 0; i < mtbf.Length; i++)
            {
                availability[i] = CD_Availability(mtbf[i], mttr[i]);

                seriesAvailability *= availability[i];
            }

            return seriesAvailability;
        }
    }
}
